import { message as Message } from '../components/q-message/message';

// 匹配表情特殊字符
export const emoji =
    /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi;

// 匹配（允许字母、数字、下划线）
export const lun = /^\w+$/;

// 匹配（允许字母、数字、英文符号）
export const password = /^[a-zA-Z0-9!@#$%^&*()_+\-=[\]{}|';":,.<>/?]+$/;

// 身份证号码
export const id_no = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/;

// 手机号码
export const mobile = /^1[3456789]\d{9}$/;

// 固定号码
export const tele_phone = /^(0\d{2,3}\-)?([2-9]\d{6,7})+(\-\d{1,6})?$/;

// 手机号码 or 固定号码
export const mobile_or_tel = /^1[3456789]\d{9}$|^(0\d{2,3}\-)?([2-9]\d{6,7})+(\-\d{1,6})?$/;

// 邮箱
export const email = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;

class Validate {
    // 匹配 数字、字母、下划线
    LUN(str: string) {
        return lun.test(str);
    }
    // 匹配 身份证号
    ID_NO(str: string) {
        return id_no.test(str);
    }
    // 匹配 邮箱 email
    EMAIL(str: string) {
        return email.test(str);
    }
    // 匹配 手机号
    MOBILE(str: string) {
        return mobile.test(str);
    }
    // 匹配 固定电话
    TELEPHONE(str: string) {
        return tele_phone.test(str);
    }
    // 匹配 手机号 or 固定电话
    MOBILE_OR_TELEPHONE(str: string) {
        return mobile_or_tel.test(str);
    }
}
// 校验
export const validate = new Validate();

// element 表单校验
export const validateEmoji = (_: any, value: string, callback: (option?: any) => void) => {
    if (emoji.test(value)) {
        return callback(new Error('不能使用表情符号!'));
    } else {
        return callback();
    }
};

/**
 * 表单输入格式转换
 */
export class InputTransform {
    // 只能输入数字
    static onlyMobile() {
        return /[^\d]+$/;
    }

    // 只能输入表情
    static onlyEmoji() {
        return emoji;
    }

    // 只能输入字母
    static onlyLetter() {
        return /[\u4e00-\u9fa5/\s+/]|[`~!@#$%^&*() \\+ =<>?"{}|, \\/ ;' \\ [ \] ·~！@#￥%……&*（）—— \\+ ={}|《》？：“”【】、；‘’，。、_.-:]/g;
    }

    // 只能输入汉字、英文、数字
    static onlyCnEnLetter() {
        return /[^a-zA-Z0-9\u4E00-\u9FA5]/g;
    }

    // 只允许输入数字、字母
    static onlyNumLetter() {
        return /[\u4e00-\u9fa5/\s+/]|[^a-zA-Z0-9\u4E00-\u9FA5]/g;
    }

    // 只允许输入数字、字母、符号
    static numericAlphabetSymbols() {
        return /[\u4e00-\u9fa5\s]|[^a-zA-Z0-9\u4E00-\u9FA5] | [`~!@#$%^&*()\\+=<>?"{}|, \/;' [\]·~！@#￥%……&*（）—— \\+ ={}|《》？：“”【】、；‘’，。、_.-:\/]/g;
    }

    // 只允许输入中文
    static onlyChinese() {
        return /[^\u4e00-\u9fa5]/g;
    }
}

/**
 * 表单验证
 */
export const StrategyKey = {
    IS_EMPTY: 'isEmpty',
    IS_MOBILE: 'isMobile',
    IS_TELEPHONE: 'isTelePhone',
    IS_MOBILE_OR_TELEPHONE: 'isMobileOrTelephone',
    IS_EMIAL: 'isEmail',
    IS_LONGERTHAN_MIINLEN: 'isLongerThanMinLength',
    IS_CUSTOMIZE: 'isCustomize'
} as const;

type Shape = typeof StrategyKey;

// 从对象的键 (IS_EMPTY | IS_MOBILE | IS_LONGERTHAN_MIINLEN) 创建一个联合类型
type Shapes = keyof Shape;

// 从对象的值 (isEmpty | isMobile | isLongerThanMinLength) 创建一个联合类型
export type ValidKey = Shape[Shapes];

export interface RuleFn {
    ruleFn?: (fieldVal: StrategyParams, msg: string) => string | undefined;
}

export interface ValidFn {
    resetAllValid: () => void;
}
export interface StrategyParams extends RuleFn {
    value: string | Array<any>;
    dataId?: string;
    id?: string;
    len?: number;
    row?: number;
    label?: string;
    type?: ValidKey;
    validFn?: ValidFn;
    tableInstance?: any;
}

/**
 * 表格项校验实现逻辑
 */
const strategy = {
    [StrategyKey.IS_EMPTY]: function ({ value }: StrategyParams, errMsg: string) {
        if (value === '' || value == null || (Array.isArray(value) && !value.length)) {
            return errMsg;
        }
    },
    [StrategyKey.IS_MOBILE]: function ({ value }: StrategyParams, errMsg: string) {
        if (value && !validate.MOBILE(value as string)) {
            return errMsg;
        }
    },
    [StrategyKey.IS_TELEPHONE]: function ({ value }: StrategyParams, errMsg: string) {
        if (value && !validate.TELEPHONE(value as string)) {
            return errMsg;
        }
    },
    [StrategyKey.IS_MOBILE_OR_TELEPHONE]: function ({ value }: StrategyParams, errMsg: string) {
        if (value && !validate.MOBILE_OR_TELEPHONE(value as string)) {
            return errMsg;
        }
    },
    [StrategyKey.IS_EMIAL]: function ({ value }: StrategyParams, errMsg: string) {
        if (value && !validate.EMAIL(value as string)) {
            return errMsg;
        }
    },
    [StrategyKey.IS_LONGERTHAN_MIINLEN]: function ({ value, len }: StrategyParams, errMsg: string) {
        if ((value as string).length < len!) {
            return errMsg;
        }
    },
    // 自定义校验验证
    [StrategyKey.IS_CUSTOMIZE]: function (params: StrategyParams, errMsg: string) {
        if (params.ruleFn) {
            return params.ruleFn(params, errMsg);
        }
    }
};

interface validateItems {
    params: StrategyParams;
    strategyKey: ValidKey;
    errMsg: string;
}

/**
 * 表格校验实例
 */
export class Valid {
    private _validateItems: Array<validateItems>;

    constructor() {
        this._validateItems = [];
    }

    // 添加验证选项
    add(params: StrategyParams, strategyKey: ValidKey, errMsg: string) {
        this._validateItems.push({ params, strategyKey, errMsg });
    }

    // 开始验证各验证项
    start() {
        for (const item of this._validateItems) {
            const { params, strategyKey, errMsg } = item;

            const msg = strategy[strategyKey](params, errMsg);

            if (msg) {
                return {
                    errMsg: msg,
                    params
                };
            }
        }
    }

    // 是否存在该校验
    isHaveValidItem(key: ValidKey) {
        const filterValidItem = this._validateItems.filter(
            (item: validateItems) => item.strategyKey === key
        );
        return !!filterValidItem.length;
    }
}

/**
 * 单例模式
 */
export class SingleInstance {
    constructor(fn: any) {
        let singleInstance: any;
        function SingleConstructor(...args: any) {
            // 第一次实例化
            if (!singleInstance) {
                singleInstance = new (fn as any)(...args);
            }
            // 多次实例化直接返回
            return singleInstance;
        }

        SingleConstructor.prototype = Object.create(fn.prototype);

        return SingleConstructor;
    }
}

/**
 * 校验错误提示框实例
 */
let closeInstance: (() => void) | null;
export const validErrorMessage = (errMsg: string) => {
    if (closeInstance) {
        closeInstance = null;
        return;
    }

    closeInstance = Message.error(errMsg);

    // 下个任务进行实例还原，避免单实例连续点击中间不出现错误弹出层
    nextTick(() => {
        closeInstance = null;
    });
};

/**
 * 替换特殊符号
 */
type FormData = Record<string, any>;
export enum InputType {
    EMOJI = 'onlyEmoji',
    NUMBER = 'onlyMobile',
    LETTER = 'onlyLetter',
    CNENLETTER = 'onlyCnEnLetter',
    NUMERLETTR = 'onlyNumLetter',
    NUMDECIMAL = 'onlyNumDecimals',
    NUMERIC_ALPHABET_SYMBOLS = 'numericAlphabetSymbols',
    CHINESE = 'chinese'
}

export type InputTypeValue = `${InputType}`;

const inputTypeMap: FormData = {
    [InputType.EMOJI]: InputTransform.onlyEmoji,
    [InputType.NUMBER]: InputTransform.onlyMobile,
    [InputType.LETTER]: InputTransform.onlyLetter,
    [InputType.CNENLETTER]: InputTransform.onlyCnEnLetter,
    [InputType.NUMERLETTR]: InputTransform.onlyNumLetter,
    [InputType.NUMERIC_ALPHABET_SYMBOLS]: InputTransform.numericAlphabetSymbols,
    [InputType.CHINESE]: InputTransform.onlyChinese
};

const inputFormatTip: FormData = {
    [InputType.NUMBER]: '仅支持输入数字',
    [InputType.LETTER]: '仅支持输入字母',
    [InputType.CNENLETTER]: '仅支持输入汉字、数字、字母',
    [InputType.NUMERLETTR]: '仅支持输入数字、字母',
    [InputType.NUMERIC_ALPHABET_SYMBOLS]: '仅支持输入数字、字母或英文符号',
    [InputType.CHINESE]: '仅支持输入中文'
};

/**
 * 传入格式类型，只能输入对应格式类型
 */
interface PopoverFn {
    showErrorPopover: (errMsg: string) => void;
    hideErrorPopover: () => void;
}
let timer: number | undefined;
export const formatInput = (
    formData: FormData,
    key: string,
    type: string = InputType.EMOJI,
    popOverFn?: PopoverFn
) => {
    if (formData[key] == null) return;

    if (type !== InputType.EMOJI) {
        formData[key] = formData[key].replace(inputTypeMap[InputType.EMOJI](), ''); // 默认禁止输入表情
    }

    // 给相对应的输入错误格式给与提示
    const reg = inputTypeMap[type]();
    if (popOverFn) {
        clearTimeout(timer);
        if (reg.test(formData[key])) {
            formData.formatError = true;
            popOverFn.showErrorPopover(inputFormatTip[type] || '输入格式不正确');
        }

        timer = window.setTimeout(() => {
            formData.formatError = false;
            popOverFn.hideErrorPopover();
        }, 2000);
    }

    return formData[key].replace(reg, '');
};
